// https://indepth.dev/posts/1007/the-how-and-why-on-reacts-usage-of-linked-list-in-fiber-to-walk-the-components-tree

function log(value) {
	console.log(value.name)
}

const a1 = {name: 'a1'};
const b1 = {name: 'b1'};
const b2 = {name: 'b2'};
const b3 = {name: 'b3'};
const c1 = {name: 'c1'};
const c2 = {name: 'c2'};
const d1 = {name: 'd1'};
const d2 = {name: 'd2'};

a1.render = () => [b1, b2, b3];
b1.render = () => null;
b2.render = () => [c1];
b3.render = () => [c2];
c1.render = () => [d1, d2];
c2.render = () => null;
d1.render = () => null;
d2.render = () => null;

class Node {
    constructor(instance) {
        this.instance = instance;
        this.child = null;
        this.sibling = null;
        this.return = null;
    }
}

function link(parent, elements) {
    if (elements === null) elements = [];

    parent.child = elements.reduceRight((previous, current) => {
        const node = new Node(current);
        node.return = parent;
        node.sibling = previous;
        return node;
    }, null);

    return parent.child;
}

let nextUnitOfWork = new Node(a1)

workLoop()

function workLoop() {
	while(nextUnitOfWork !== null) {
		nextUnitOfWork = performUnitOfWorker(nextUnitOfWork)
	}
}

function performUnitOfWorker(workInProgress) {
	let next = beginWork(workInProgress)
	if (next === null) {
		next = completeUnitOfWork(workInProgress)
	}

	return next
}

function beginWork(workInProgress) {
	// 返回子项
	const children = workInProgress.instance.render()
	// 构造指针 并返回子节点
	return link(workInProgress, children)
}

function completeUnitOfWork(workInProgress) {
	// 没有子项，肯定有兄弟节点
	while(true) {
		let returnFiber = workInProgress.return
		let siblingFiber = workInProgress.sibling

		nextUnitOfWork = completeWork(workInProgress);

		if (siblingFiber !== null) {
			return siblingFiber
		} else if (returnFiber !== null) {
			workInProgress = returnFiber
			continue
		} else {
			return null
		}
	}
}

function completeWork(workInProgress) {
	log(workInProgress.instance)
	return null
}